package com.example.websocketserver.configuration.interceptors;

import com.alibaba.fastjson.JSON;
import com.example.websocketserver.pojo.HomeHubWebsocketPrincipal;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.messaging.simp.SimpMessageType;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.stereotype.Component;

/**
 * Stomp连接拦截器
 *
 * @author liulei
 * @version 1.0
 */
/**
 * Stomp连接拦截器
 *
 * @author liulei
 * @version 1.0
 */
@Slf4j
@Component
public class StompUserInterceptor implements ChannelInterceptor {

    @SneakyThrows
    @Override
    public Message<?> preSend(Message<?> message, MessageChannel channel) {
        MessageHeaders headers = message.getHeaders();
        validatedAuthPrinciple(headers);
        return message;
    }

    @Override
    public void postSend(Message<?> message, MessageChannel channel, boolean sent) {
    }

    @SneakyThrows
    @Override
    public void afterSendCompletion(Message<?> message, MessageChannel channel, boolean sent, @Nullable Exception ex) {
        MessageHeaders headers = message.getHeaders();
        SimpMessageType messageType = SimpMessageType.valueOf(String.valueOf(headers.get(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER)));
        if (messageType.equals(SimpMessageType.HEARTBEAT)) {
            return;
        }
        HomeHubWebsocketPrincipal principal = validatedAuthPrinciple(headers);
        String destination = String.valueOf(headers.get(SimpMessageHeaderAccessor.DESTINATION_HEADER));
        if (SimpMessageType.CONNECT.equals(messageType)) {
            // TODO 分布式环境下在线人数统计
            log.info("websocket->communication -> user connect succeed {}", principal.getName());
            return;
        }
        if (SimpMessageType.SUBSCRIBE.equals(messageType)) {
            log.info("websocket->communication-> user subscribe succeed {}|{}", principal.getName(), destination);
            return;
        }
        if (SimpMessageType.UNSUBSCRIBE.equals(messageType)) {
            log.info("websocket->communication-> user subscribe lost connect {}|{}", principal.getName(), destination);
            return;
        }
        if (SimpMessageType.DISCONNECT.equals(messageType)) {
            log.info("websocket->communication-> user disconnected {}", principal.getName());
            return;
        }
        log.info("websocket->communication-> message send success :{}|{}|{}|{}", principal.getName(), messageType, destination, new String((byte[]) message.getPayload()));
    }

    @Override
    public boolean preReceive(MessageChannel channel) {
        return true;
    }

    @Override
    public Message<?> postReceive(Message<?> message, MessageChannel channel) {
        return message;
    }

    @SneakyThrows
    @Override
    public void afterReceiveCompletion(Message<?> message, MessageChannel channel, Exception ex) {
        MessageHeaders headers = message.getHeaders();
        String destination = String.valueOf(headers.get(SimpMessageHeaderAccessor.DESTINATION_HEADER));
        HomeHubWebsocketPrincipal principal = validatedAuthPrinciple(headers);
        log.info("websocket->communication-> message receive success:{}|{}|{}", principal.getName(), destination, new String((byte[]) message.getPayload()));
    }

    /**
     * 用户鉴权
     */
    private HomeHubWebsocketPrincipal validatedAuthPrinciple(MessageHeaders headers) {
        HomeHubWebsocketPrincipal principal = (HomeHubWebsocketPrincipal) headers.get(SimpMessageHeaderAccessor.USER_HEADER);
        if (headers.get(SimpMessageHeaderAccessor.USER_HEADER) == null) {
            String json = JSON.toJSONString(headers.get(SimpMessageHeaderAccessor.SESSION_ATTRIBUTES));
            try {
                principal = JSON.parseObject(json, HomeHubWebsocketPrincipal.class);
            } catch (Exception e) {
                log.error("websocket user info transfer error {}", json, e);
            }
        }
        if (principal == null) {
            log.error("websocket->communication-> user not exist");
            throw new RuntimeException("websocket认证失败");
        }
        return principal;
    }
}
